package com.babble.comment.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.babble.comment.conversion.CommentMapper;
import com.babble.comment.dto.CommentDTO;
import com.babble.comment.dto.QueryCommentDTO;
import com.babble.comment.entity.Comment;
import com.babble.comment.entity.UserCommentInfo;
import com.babble.comment.repository.CommentRepository;
import com.babble.comment.service.ICommentService;
import com.babble.comment.vo.CommentVO;
import com.babble.comment.vo.UserCommentsVO;
import com.babble.user.dto.UserOrToUserDTO;
import com.babble.user.feign.IUserClient;
import com.github.houbb.sensitive.word.core.SensitiveWordHelper;
import lombok.RequiredArgsConstructor;
import org.springblade.common.cache.CacheNames;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.RedisUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 评论模块服务实现
 *
 * @author wm
 */
@Service
@RequiredArgsConstructor
public class ICommentServiceImpl implements ICommentService {
	private final CommentRepository commentRepository;
	private final CommentMapper commentMapper;
	private final IUserClient userClient;
	private final MongoTemplate mongoTemplate;
	private final RedisUtil redisUtil;

	@Override
	public Page<CommentVO> list(String id, int source, org.springblade.core.mp.support.Query query) {
		//mogodb分页，默认页数为0，需+1，根据创建时间倒序
		PageRequest page = PageRequest.of(query.getCurrent() - 1, query.getSize(), Sort.Direction.DESC, "create_time");
		//判断为留言板评论直接设置静态id
		if (source == 3) {
			id = CommonConstant.COMMENT_MESSAGE_BOARD;
		}
		List<CommentVO> rCommentVOS = (List<CommentVO>) redisUtil.get(CacheNames.COMMENT_KEY + id + ":" + query.getCurrent() + "_" + query.getSize());
		if (rCommentVOS != null) {
			long total = commentRepository.countByBlogIdAndSourceAndParentIdIsNull(id, source);
			return PageableExecutionUtils.getPage(rCommentVOS, page, () -> total);
		}
		Page<Comment> commentsPage = commentRepository.findAllByBlogIdAndSourceAndParentIdIsNull(id, source, page);
		List<CommentVO> commentVOS = commentsPage.stream().parallel().map(comment -> {
			//一级评论
			CommentVO commentVO = commentMapper.commentToCommentVo(comment);
			//判断是否有当前用户信息缓存
			UserCommentInfo user = (UserCommentInfo) redisUtil.get(CacheNames.COMMENT_GET_USERINFO + comment.getUserId());
			if (user == null) {//远程获取用户信息
				R<UserOrToUserDTO> userInfo = userClient.userInfoOrToUserinfo(comment.getUserId(), null);
				if (userInfo.isSuccess()) {
					UserOrToUserDTO userOrToUserDTO = userInfo.getData();
					user = UserCommentInfo.builder().avatar(userOrToUserDTO.getAvatar()).nickName(userOrToUserDTO.getNickName()).build();
					redisUtil.set(CacheNames.COMMENT_GET_USERINFO + comment.getUserId(), user, RandomUtil.randomInt(20, 30), TimeUnit.MINUTES);
				}
			}
			List<CommentVO> childerCommentVOS = getCommentVOS(comment.getId());
			//父级评论添加信息
			commentVO.setAvatar(user.getAvatar());
			commentVO.setNickName(user.getNickName());
			commentVO.setChildren(childerCommentVOS);
			return commentVO;
		}).collect(Collectors.toList());

		redisUtil.set(CacheNames.COMMENT_KEY + id + ":" + query.getCurrent() + "_" + query.getSize(), commentVOS, RandomUtil.randomInt(5, 10), TimeUnit.MINUTES);
		return PageableExecutionUtils.getPage(commentVOS, page, commentsPage::getTotalElements);
	}


	@Override
	public Comment create(CommentDTO commentDTO) {
		BladeUser user = SecureUtil.getUser();
		Comment comment = commentMapper.commentDtoToComment(commentDTO);
		//判断为留言板评论直接设置静态id
		if (comment.getSource() == 3) {
			comment.setParentId(CommonConstant.COMMENT_MESSAGE_BOARD);
		}
		comment.setUserId(String.valueOf(user.getUserId()));
//		comment.setUserId(RandomUtil.randomNumbers(19));
		//过滤违规词
		String content = SensitiveWordHelper.replace(comment.getContent(), CommonConstant.SENSITIVE_WORD_REPLACE);
		comment.setContent(content);
		//新增数据根据前缀博客id进行清空缓存
		redisUtil.del(CacheNames.COMMENT_KEY + comment.getBlogId() + ":*");
		return commentRepository.save(comment);
	}

	@Override
	@Transactional(rollbackFor = ServiceException.class)
	public void delete(String id, String blogId) {
		commentRepository.deleteById(id);
		commentRepository.deleteAllByParentId(id);
		redisUtil.del(CacheNames.COMMENT_KEY + blogId + ":*");
	}

	@Override
	@Transactional(rollbackFor = ServiceException.class)
	public void delete(List<String> ids) {
		commentRepository.deleteAllById(ids);
		commentRepository.deleteAllByParentIdIn(ids);
		redisUtil.del(CacheNames.COMMENT_KEY + "*");
	}

	@Override
	public UserCommentsVO getUserComments() {
		BladeUser user = SecureUtil.getUser();
		List<Comment> comments = commentRepository.findAllByUserIdOrderByCreateTimeDesc(String.valueOf(user.getUserId()));
		List<Comment> replies = commentRepository.findAllByParentIdOrderByCreateTimeDesc(String.valueOf(user.getUserId()));
		return UserCommentsVO.builder()
			.comments(comments)
			.replies(replies)
			.build();
	}

	@Override
	public Page<CommentVO> queryPage(QueryCommentDTO queryComment) {
		Criteria criteria = new Criteria();
		//查询条件
		if (Func.isNotEmpty(queryComment.getContent())) {
			Pattern pattern = Pattern.compile("^.*" + queryComment.getContent() + ".*$", Pattern.CASE_INSENSITIVE);
			criteria.and("content").regex(pattern);
		}
		if (Func.isNotEmpty(queryComment.getSource())) {
			criteria.and("source").is(queryComment.getSource());
		}
		if (Func.isNotEmpty(queryComment.getBlogId())) {
			criteria.and("blog_id").is(queryComment.getBlogId());
		}
		if (Func.isNotEmpty(queryComment.getUserId())) {
			criteria.and("user_id").is(queryComment.getUserId());
		}
		Sort.Direction sort = Sort.Direction.DESC;
		if ("asc".equalsIgnoreCase(queryComment.getAscs())) {
			sort = Sort.Direction.ASC;
		}
		Query query = new Query(criteria);
		//分页条件
		PageRequest pageable = PageRequest.of(queryComment.getCurrent() - 1, queryComment.getSize(), sort, "create_time");
		//获取查询条件总数
		long count = mongoTemplate.count(query, Comment.class);
		List<Comment> comments = mongoTemplate.find(query.with(pageable), Comment.class);
		List<CommentVO> commentVOS = comments.stream().map(comment -> {
			CommentVO commentVO = commentMapper.commentToCommentVo(comment);
			R<UserOrToUserDTO> userOrToUserDTOR = userClient.userInfoOrToUserinfo(comment.getUserId(), comment.getToUserId());
			if (userOrToUserDTOR.isSuccess()) {
				UserOrToUserDTO userOrToUserDTO = userOrToUserDTOR.getData();
				commentVO.setAvatar(userOrToUserDTO.getAvatar());
				commentVO.setNickName(userOrToUserDTO.getNickName());
				commentVO.setToAvatar(userOrToUserDTO.getToAvatar());
				commentVO.setToNickName(userOrToUserDTO.getToNickName());
			}
			return commentVO;
		}).collect(Collectors.toList());
		//封装分页
		return PageableExecutionUtils.getPage(commentVOS, pageable, () -> count);
	}

	/**
	 * 获取二级评论信息
	 *
	 * @param id 父级评论id
	 * @return
	 */
	private List<CommentVO> getCommentVOS(String id) {
		//二级评论
		List<Comment> childrenComments = commentRepository.findAllByParentIdOrderByCreateTimeDesc(id);
		return childrenComments.stream().parallel().map(comment -> {
			CommentVO commentVO = commentMapper.commentToCommentVo(comment);
			//判断是否有当前用户信息缓存
			UserCommentInfo user = (UserCommentInfo) redisUtil.get(CacheNames.COMMENT_GET_USERINFO + comment.getUserId());
			UserCommentInfo userParent = (UserCommentInfo) redisUtil.get(CacheNames.COMMENT_GET_USERINFO + comment.getToUserId());
			R<UserOrToUserDTO> userOrToUserDTOR;
			if (user == null && userParent == null) {
				userOrToUserDTOR = userClient.userInfoOrToUserinfo(comment.getUserId(), comment.getToUserId());
				if (userOrToUserDTOR.isSuccess()) {
					UserOrToUserDTO userOrToUserDTO = userOrToUserDTOR.getData();
					user = UserCommentInfo.builder().avatar(userOrToUserDTO.getAvatar()).nickName(userOrToUserDTO.getNickName()).build();
					userParent = UserCommentInfo.builder().avatar(userOrToUserDTO.getToAvatar()).nickName(userOrToUserDTO.getToNickName()).build();
					redisUtil.set(CacheNames.COMMENT_GET_USERINFO + comment.getUserId(), user, RandomUtil.randomInt(20, 30), TimeUnit.MINUTES);
					redisUtil.set(CacheNames.COMMENT_GET_USERINFO + comment.getToUserId(), userParent, RandomUtil.randomInt(20, 30), TimeUnit.MINUTES);
				}
			} else if (user == null) {
				userOrToUserDTOR = userClient.userInfoOrToUserinfo(comment.getUserId(), null);
				if (userOrToUserDTOR.isSuccess()) {
					UserOrToUserDTO userOrToUserDTO = userOrToUserDTOR.getData();
					user = UserCommentInfo.builder().avatar(userOrToUserDTO.getAvatar()).nickName(userOrToUserDTO.getNickName()).build();
					redisUtil.set(CacheNames.COMMENT_GET_USERINFO + comment.getUserId(), user, RandomUtil.randomInt(20, 30), TimeUnit.MINUTES);
				}
			} else if (userParent == null) {
				userOrToUserDTOR = userClient.userInfoOrToUserinfo(comment.getParentId(), null);
				if (userOrToUserDTOR.isSuccess()) {
					UserOrToUserDTO userOrToUserDTO = userOrToUserDTOR.getData();
					userParent = UserCommentInfo.builder().avatar(userOrToUserDTO.getAvatar()).nickName(userOrToUserDTO.getNickName()).build();
					redisUtil.set(CacheNames.COMMENT_GET_USERINFO + comment.getUserId(), userParent, RandomUtil.randomInt(20, 30), TimeUnit.MINUTES);
				}
			}
			commentVO.setAvatar(user.getAvatar());
			commentVO.setNickName(user.getNickName());
			commentVO.setToAvatar(userParent.getAvatar());
			commentVO.setToNickName(userParent.getNickName());
			return commentVO;
		}).collect(Collectors.toList());
	}
}



